#!/usr/local/bin/perl -w
use strict;
use Time::HiRes qw(gettimeofday);

my $PI = 2 * atan2(1,1);

my @m = qw(	health 	damage	speed	accuracy	vulner	mobility	stealth	aiming	spread	square	);
my $war = [
[qw(grena	100		150		0		0			90		0			5		20		60		70		)],
[qw(storm	100		80		0		0			100		40			0		40		80		0		)],
[qw(snipe	100		50		0		30			70		0			10		90		100		0		)],
[qw(chass	100		70		0		0			50		0			25		60		80		0		)],
[qw(shoot	100		80		80		0			90		0			5		30		60		0		)],
];
my $peace = [
[qw(medic	50		0		0		0			100		20			0		0		0		0		)],
[qw(tuner	80		0		0		0			100		0			30		0		0		0		)],
[qw(carry	100		0		0		0			100		0			50		0		0		0		)],
[qw(sergn	120		0		0		0			100		20			0		0		0		0		)],
[qw(techn	80		0		0		0			100		0			50		0		0		0		)],
[qw(worke	200		0		0		0			100		0			50		0		0		0		)],
[qw(instr	50		0		0		0			100		0			50		0		0		0		)],
];
my %war;
my %peace;
for(@$war){
	my $u = shift @$_;
	@{$war{$u}}{@m} = @$_;
}
for(@$peace){
	my $u = shift @$_;
	@{$peace{$u}}{@m} = @$_;
}
sub compare {
	my ($v1,$v2) = @_;
	my $r = rand();
	if($r < 0.05){
		return 1;
	}elsif($r > 0.95){
		return 0;
	}else{
		return disp($v1) > disp($v2);
	}
}
sub disp {
	my $val = shift;
	return $val * (0.8 + 0.4 * rand());
}
sub disp2 {
	my $val = shift;
	my $r = rand();
	my $k = (($r**(1/3))*3 + $r/5) / 3;
	return $val * $k;
}
sub calc {
	my ($u1,$u2) = @_;
	my $hit;
	unless(rand(100) < $u2->{mobility}){
		$hit = compare($u1->{aiming},$u2->{stealth});
	}
	unless($hit){
		$hit = rand(100) < $u1->{square};
	}
	my $damag = 0;
	if($hit){
		if(rand(100) < $u1->{accuracy}){
			$damag = $u2->{current};
		}else{
			my $base = disp($u1->{damage});
			my $spr = disp($u1->{spread})/100;
			my $vuln = disp($u2->{vulner})/100;
			#print "$base $spr $vuln\n";
			$damag =  $base * $spr * $vuln;
		}
	}
	if($damag > $u2->{current}){
		$damag = $u2->{current};
	}
	$u2->{current} -= $damag;
	return $damag;
}
sub hit {
	my ($u1,$u2) = @_;
	$u1->{_speed} = $u1->{speed};
	{
		calc($u1,$u2);
		if($u2->{current} <= 0){
			return 0;
		}
		if(rand(100) < $u1->{_speed}){
			$u1->{_speed} /= 2;
			redo;
		}
	}
	return 1;
}
sub turn {
	my ($u1,$u2) = @_;
	my $turn = 0;
	{
		$turn++;
		if(hit($u1,$u2) and $turn < 100){
			redo;
		}
	}
	return $turn;
}

sub check {
	my ($u1,$u2) = @_;
	$u2->{current} = $u2->{health};
	return turn($u1,$u2);
}
sub test {
	my ($u1,$u2,$cnt) = @_;
	my $r = 0;
	for(1 .. $cnt){
		$r += check($u1,$u2);
	}
	$r /= $cnt;
	return $r;
}
sub count {
	my $round = shift;
	my @war = keys %war;
	my $battle = 0;
	my $self = "";
	for(my $i = 0; $i < @war; $i++){
		my $row = "";
		for(my $j = 0; $j < @war; $j++){
			my $u1 = $war[$i];
			my $u2 = $war[$j];
			my $r1 = test($war{$u1},$war{$u2},$round);
			my $r2 = test($war{$u2},$war{$u1},$round);
			my $f1 = $r2 / $r1 > 1.0 ? "*":" ";
			my $f2 = $r1 / $r2 > 1.0 ? "*":" ";
			my $str = sprintf "%s%s %s%s %3.1f:%3.1f\n",$u1,$f1,$u2,$f2,$r1,$r2;
			if($u1 eq $u2){
				$self .= $str;
			}else{
				$row .= $str;
			}
			$battle++;
		}
		print $row;
		print "\n";
	}
	print $self;
	print "\n";

	return $battle;

	my @peace = keys %peace;
	for(my $i = 0; $i < @war; $i++){
		my $row = "";
		for(my $j = 0; $j < @peace; $j++){
			my $u1 = $war[$i];
			my $u2 = $peace[$j];
			my $r1 = test($war{$u1},$peace{$u2},$round);
			$row .= sprintf "%s %s %3.1f\n",$u1,$u2,$r1;
			$battle++;
		}
		print $row;
		print "\n";
	}
	print "\n";
	return $battle;
}
my $try = 1000;
my $r0 = gettimeofday;
my $battle = count($try);
my $r1 = gettimeofday;
printf "%.2f b/s\n", $battle*$try/($r1-$r0);
